#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QColorDialog>
#include <QLabel>
#include <QFileDialog>
#include <QMessageBox>
#include <QPushButton>
#include <QCloseEvent>
#include <QTextStream>

#include "openglpaintingarea.h"
namespace Node {
    class Pic;

    extern struct ControlMode cMode;
    extern struct PainterState pState;
    extern class Pic * patterns;
    extern class Pic * tail;
    extern class Pic * tempPic;
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    isUnsaved = true;
    curFile = tr("未命名.ops");

    // 设置窗口标题
    setWindowTitle(QString("Opengl Painting System"));
    // 临时信息，如一般的提示信息，上面讲到的动作提示就是临时信息；正常信息，如显示页数和行号；永久信息，如显示版本号或者日期
    // showMessage()函数来显示一个临时消息，它会出现在状态栏的最左边
    //ui->statusBar->showMessage(tr("Painting!"), 2000);
    // addWidget()函数添加一个QLabel到状态栏上用于显示正常信息
    statusLabel = new QLabel;
    statusLabel->setMinimumSize(100, 20); // 设置标签最小大小
    statusLabel->setFrameShape(QFrame::WinPanel); // 设置标签形状
    statusLabel->setFrameShadow(QFrame::Sunken); // 设置标签阴影
    ui->statusBar->addWidget(statusLabel);
    statusLabel->setText(tr("绘图系统"));
    // 显示永久信息，要使用addPermanentWidget()函数来添加一个如QLabel一样的可以显示信息的部件
    // 它会生成在状态栏的最右端，不会被临时消息所掩盖
    permanent = new QLabel;
    permanent->setFrameStyle(QFrame::Box | QFrame::Sunken);
    permanent->setText(tr("<a href=\"https://chenxfeng.github.io\">chenxfeng.github.io</a>"));
    permanent->setTextFormat(Qt::RichText);
    permanent->setOpenExternalLinks(true);
    ui->statusBar->addPermanentWidget(permanent);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::closeEvent(QCloseEvent *event) {
    if (!isUnsaved) return ;
    QMessageBox box;
    box.setWindowTitle(tr("警告"));
    box.setIcon(QMessageBox::Warning);
    box.setText(curFile + tr(" 尚未保存，是否保存？"));
    QPushButton *yesBtn = box.addButton(tr("是(&Y)"), QMessageBox::YesRole);
    box.addButton(tr("否(&N)"), QMessageBox::NoRole);
    QPushButton *cancelBut = box.addButton(tr("取消"), QMessageBox::RejectRole);
    box.exec();
    if (box.clickedButton() == yesBtn) {
        //qDebug() << "good";
        on_actionsave_triggered();
        event->accept();
    }
    else if (box.clickedButton() == cancelBut) {
        //qDebug() << "dog";
        event->ignore();
    }
}

void MainWindow::on_actionsave_triggered() {
    // 保存文件
    QString fileName = QFileDialog::getSaveFileName(this, tr("另存为"),
                                                    curFile,
                                                    tr("Opengl-Painting-System(*.ops);;All(*)"));
    // do save work
    if (fileName.isEmpty()) {
        return ;
    }
    if (saveFile(fileName))
        isUnsaved = false;
    statusLabel->setText(fileName);
}

bool MainWindow::saveFile(const QString &fileName) {
    QFile file(fileName);
    if (!file.open(QFile::WriteOnly | QFile::Text)) {
        // %1 %2 对应两个arg参数
        QMessageBox::warning(this, tr("opengl绘图系统"), tr("无法写入文件 %1: /n %2")
            .arg(fileName).arg(file.errorString()));
        return false;
    }
    QTextStream out(&file);
    // 鼠标变为等待状态
    //QApplication::setOverrideCursor(Qt::WaitCursor);

    Node::Pic * p = Node::patterns->next;

    while (p != NULL) {
        out << p->type << "\n";
        out << p->render_type << "\n";
        out << p->v_size << "\n";
        for (unsigned int i = 0; i < p->v_size/sizeof(GLfloat); ++i)
            out << p->verts[i] << " ";
        out << "\n";
        out << p->i_size << "\n";
        for (unsigned int i = 0; i < p->i_size/sizeof(GLushort); ++i)
            out << p->indices[i] << " ";
        out << "\n";
        out << p->rgb[0] << " " << p->rgb[1] << " " << p->rgb[2] << "\n";

        p = p->next;
        out << "\n";
    }

    // 鼠标指针恢复原来的状态
    //QApplication::restoreOverrideCursor();
    //isUntitled = false;
    // 文件标准路径
    curFile = QFileInfo(fileName).canonicalFilePath();
    return true;
}

void MainWindow::on_actionopen_triggered() {
    // 打开文件
    QString fileName = QFileDialog::getOpenFileName(this, tr("打开"),
                                                    ".",
                                                    tr("Opengl-Painting-System(*.ops);;All(*)"));
    // do open work
    if (fileName.isEmpty()) {
        return ;
    }
    if (loadFile(fileName))
        isUnsaved = true;
    statusLabel->setText(fileName);
}

bool MainWindow::loadFile(const QString &fileName) {
    QFile file(fileName);
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        QMessageBox::warning(this, tr("opengl绘图系统"), tr("无法读取文件 %1:\n%2.").arg(fileName).arg(file.errorString()));
        return false; // 只读方式打开文件 出错返回
    }
    if (fileName.right(4) != ".ops") {
        QMessageBox::warning(this, tr("Warning"), tr("wrong file type"));
        //qDebug() << "Wrong filename";
        return false;
    }
    QTextStream in(&file);

    // clear the previous primitives
    Node::Pic * psuHead = Node::patterns;
    Node::Pic * toBeDel = psuHead->next;
    while (toBeDel != NULL) {
        psuHead = psuHead->next;
        delete toBeDel;
        toBeDel = psuHead;
    }
    Node::patterns->next = NULL;
    // new primitives
    Node::Pic * p = Node::patterns;
    while (!in.atEnd()) {
        p->next = new Node::Pic;
        p->next->prev = p; // doubly-link list
        p = p->next;
        p->next = NULL;
        in >> p->type;
        in >> p->render_type;
        in >> p->v_size;
        p->verts = new GLfloat[p->v_size/sizeof(GLfloat)];
        for (unsigned int i = 0; i < p->v_size/sizeof(GLfloat); ++i)
            in >> p->verts[i];
        in >> p->i_size;
        p->indices = new GLushort[p->i_size/sizeof(GLushort)];
        for (unsigned int i = 0; i < p->i_size/sizeof(GLushort); ++i) {
            in >> p->indices[i];
        }
        in >> p->rgb[0] >> p->rgb[1] >> p->rgb[2];
        p->hasVAO = false;

        // zero points correction
        if (p->type == 0) {
            p = p->prev;
            delete p->next;
            p->next = NULL;
        }
    };

    // 设置当前文件
    curFile = QFileInfo(fileName).canonicalFilePath();
    return true;
}

void MainWindow::on_actionnew_triggered()
{
    // 新建文件
    if (isUnsaved) {
        QMessageBox box;
        box.setWindowTitle(tr("警告"));
        box.setIcon(QMessageBox::Warning);
        box.setText(curFile + tr(" 尚未保存，是否保存？"));
        QPushButton *yesBtn = box.addButton(tr("是(&Y)"), QMessageBox::YesRole);
        box.addButton(tr("否(&N)"), QMessageBox::NoRole);
        QPushButton *cancelBut = box.addButton(tr("取消"), QMessageBox::RejectRole);
        box.exec();
        if (box.clickedButton() == yesBtn) {
            //qDebug() << "good";
            on_actionsave_triggered();
        } else if (box.clickedButton() == cancelBut) {
            //qDebug() << "dog";
        }
    }

    Node::Pic * toBeDel = Node::patterns;
    while (toBeDel != NULL) {
        Node::patterns = Node::patterns->next;
        delete toBeDel;
        toBeDel = Node::patterns;
    }

    // initialize pic list
    Node::patterns = new Node::Pic;
    Node::patterns->type = 0; // a head Node
    Node::patterns->next = NULL;
    Node::patterns->prev = NULL;

    // initialize temporary pic buffer
    Node::tempPic = new Node::Pic;
    Node::tempPic->type = 0;  // unKnown type
    Node::tempPic->next = NULL;
    Node::tempPic->prev = NULL;
    Node::tempPic->hasVAO = false;

    // 到链表尾部
    Node::tail = Node::patterns;

    // initialize painter
    Node::pState.type = 0;
    Node::pState.color_R = 0.0f;
    Node::pState.color_G = 0.0f;
    Node::pState.color_B = 0.0f;
    Node::pState.render_type = 1; // default to draw graph filled

    statusLabel->setText(tr("绘图系统"));
    ui->openGLWidget->update();
}

void MainWindow::keyPressEvent(QKeyEvent *e) {
    ui->openGLWidget->keyPressEvent(e);
}

void MainWindow::on_actioncolor_triggered()
{
    // QColorDialog: Color changed only here
    QColor color = QColorDialog::getColor(Qt::black);
    if (color.isValid()) {
        Node::pState.color_R = color.redF();
        Node::pState.color_G = color.greenF();
        Node::pState.color_B = color.blueF();
    }
}

void MainWindow::on_actiontriangle_triggered()
{
    if (Node::cMode.type == 1) {
        // set painter to draw triangles
        Node::pState.type = 1;

        statusLabel->setText(tr("画一个等腰三角形"));
    }
}

void MainWindow::on_actionrectangle_triggered()
{
    if (Node::cMode.type == 1) {
        // set painter to draw triangles
        Node::pState.type = 2;

        statusLabel->setText(tr("画一个矩形"));
    }
}

void MainWindow::on_actionline_triggered()
{
    if (Node::cMode.type == 1) {
        // set painter to draw lines
        Node::pState.type = 3;

        statusLabel->setText(tr("画一条直线"));
    }
}

void MainWindow::on_actionrounded_rectangle_triggered()
{
    if (Node::cMode.type == 1) {
        // set painter to draw rounded rectangles
        Node::pState.type = 4;

        statusLabel->setText(tr("画一条圆角矩形"));
    }
}

void MainWindow::on_actioncircle_triggered()
{
    if (Node::cMode.type == 1) {
        // set painter to draw circles
        Node::pState.type = 5;

        statusLabel->setText(tr("画一条圆"));
    }
}

void MainWindow::on_actionellipse_triggered()
{
    if (Node::cMode.type == 1) {
        // set painter to draw ellipse
        Node::pState.type = 6;

        statusLabel->setText(tr("画一条椭圆"));
    }
}

void MainWindow::on_actionpolygon_triggered()
{
    if (Node::cMode.type == 1) {
        // set painter to draw polygon
        Node::pState.type = 7;

        statusLabel->setText(tr("画一条任意多边形"));
    }
}

void MainWindow::on_actioncurve_triggered()
{
    if (Node::cMode.type == 1) {
        // set painter to draw bezier-curve
        Node::pState.type = 8;

        statusLabel->setText(tr("画一条曲线"));
    }
}

void MainWindow::on_actionfill_mode_triggered()
{
    // 恢复绘图模式 : fill
    Node::pState.render_type = 0;

    statusLabel->setText(tr("绘图系统：填充模式"));
}

void MainWindow::on_actionline_mode_triggered()
{
    // 恢复绘图模式 : line
    Node::pState.render_type = 1;

    statusLabel->setText(tr("绘图系统：线框模式"));
}

void MainWindow::on_actionfill_with_border_mode_triggered()
{
    // 恢复绘图模式 : fill-with-border 带框填充图形
    Node::pState.render_type = 2;

    statusLabel->setText(tr("绘图系统：带框填充模式"));
}

void MainWindow::on_actionpainting_triggered()
{
    if (Node::cMode.pick_a_pic == false && Node::cMode.scale_a_pic == false) {
        // control mode: painting
        Node::cMode.type = 1;
        statusLabel->setText(tr("绘图系统"));
    }
}

void MainWindow::on_actionmodify_triggered()
{
    if (Node::cMode.pick_a_pic == false) {
        // control mode: scale
        Node::cMode.type = 2;
        statusLabel->setText(tr("滚轮缩放"));
    }
}

void MainWindow::on_actiondrag_triggered()
{
    if (Node::cMode.scale_a_pic == false) {
        // control mode: drag
        Node::cMode.type = 3;
        statusLabel->setText(tr("拖放图形"));
    }
}

void MainWindow::on_actionX_scale_triggered()
{
    if (Node::cMode.pick_a_pic == false) {
        // control mode: X-scale
        Node::cMode.type = 4;
        statusLabel->setText(tr("滚轮X缩放"));
    }
}

void MainWindow::on_actionY_scale_triggered()
{
    if (Node::cMode.pick_a_pic == false) {
        // control mode: Y-scale
        Node::cMode.type = 5;
        statusLabel->setText(tr("滚轮Y缩放"));
    }
}
